#include <curl/curl.h>
#include "core/http/http_helper.h"
#include "core/http/http_response.h"

namespace aliyun {

/* static */int    HttpHelper::connect_timeout_ms = 30000;
/* static */int    HttpHelper::read_timeout_ms    = 80000;
/* static */bool   HttpHelper::enable_proxy = false;
/* static */string HttpHelper::proxy_ip("");
/* static */int    HttpHelper::proxy_port = 0;


static size_t CurlWriteDataCallback(void *buffer, size_t size, size_t nmemb, void *userp) {
  HttpResponse *response = static_cast<HttpResponse*>(userp);
  #if 0 // for debug
    fprintf(stdout, "[%ld][%ld][%s]\n",size,nmemb,(char*)buffer);
  #endif
  if(response->AppendBody(static_cast<const unsigned char*>(buffer), size*nmemb)) {
    return size*nmemb;
  }
  return 0;
}

HttpResponse* HttpHelper::GetResponse(const string& url, const string& method,
  const string* post_fields, const std::map<string, string>* headers) {
  CURL *curl = curl_easy_init();
  if(NULL == curl) {
    return NULL;
  }
  HttpResponse *http_response = new HttpResponse();
  if(NULL == http_response) {
    curl_easy_cleanup(curl);
    curl = NULL;
    return NULL;
  }
  CURLcode curl_error_code = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method.c_str());;
  if(CURLE_OK == curl_error_code) {
    curl_error_code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteDataCallback);
  }
  if(CURLE_OK == curl_error_code) {
    curl_error_code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, http_response);
  }
  if(enable_proxy) {
    if(CURLE_OK == curl_error_code) {
      curl_error_code = curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
    }
    if(CURLE_OK == curl_error_code) {
      curl_error_code = curl_easy_setopt(curl, CURLOPT_PROXY, proxy_ip.c_str());
    }
    if(CURLE_OK == curl_error_code) {
      curl_error_code = curl_easy_setopt(curl, CURLOPT_PROXYPORT, proxy_port);
    }
    if(CURLE_OK == curl_error_code) {
      curl_error_code = curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
    }
  }
  if(CURLE_OK == curl_error_code) {
    curl_error_code = curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
  }
  if(CURLE_OK == curl_error_code) {
    curl_error_code = curl_easy_setopt(curl, CURLOPT_FAILONERROR, 0);
  }
  if(CURLE_OK == curl_error_code) {
    #ifdef CURLOPT_RETURNTRANSFER // for check
      curl_error_code = curl_easy_setopt(curl, CURLOPT_RETURNTRANSFER, TRUE);
    #endif
  }
  if(CURLE_OK == curl_error_code && read_timeout_ms > 0) {
    curl_error_code = curl_easy_setopt(curl, CURLOPT_TIMEOUT, read_timeout_ms);
  }
  if(CURLE_OK == curl_error_code && connect_timeout_ms > 0) {
    curl_error_code = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, connect_timeout_ms);
  }
  if(CURLE_OK == curl_error_code && url.length() > 5) {
    string scheme = url.substr(0,5);
    string_ToLower(scheme);
    if(scheme == "https") {
      curl_error_code = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
      if(CURLE_OK == curl_error_code && read_timeout_ms > 0) {
        curl_error_code = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
      }
    }
  }
  if(headers != NULL && headers->size() > 0) {
    struct curl_slist *chunk = NULL;
    std::map<string, string>::const_iterator iter;
    for(iter = headers->begin(); iter != headers->end(); iter++) {
      string header(iter->first+": "+iter->second);
      chunk = curl_slist_append(chunk, header.c_str());
    }
    if(NULL != chunk) {
      curl_error_code = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
    }
  }
  #if 0 // for debug
    if(CURLE_OK == curl_error_code) {
      curl_error_code = curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    }
  #endif
  if(CURLE_OK == curl_error_code) {
    curl_error_code = curl_easy_perform(curl);
  }
  if(CURLE_OK == curl_error_code) {
    long response_code = 0;
    curl_error_code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
    http_response->SetStatus(response_code);
  }
  if(NULL != curl) {
    curl_easy_cleanup(curl);
    curl = NULL;
  }
  if(CURLE_OK != curl_error_code) {
    delete http_response;
    http_response = NULL;
  }
  return http_response;
}

void HttpHelper::ReleaseResponse(HttpResponse *response) {
  if(NULL != response) {
    delete response;
    response = NULL;
  }
}


} // namespace aliyun {

// end of file
